package com.xxkk.logic.service;

import com.alibaba.fastjson.JSON;
import com.google.protobuf.Message.Builder;
import com.xxkk.gameCore.enums.ErrorCode;
import com.xxkk.gameCore.enums.PlayerState;
import com.xxkk.gameCore.global.globalServer.ServerData;
import com.xxkk.gameCore.global.globalServer.ServerManager;
import com.xxkk.gameCore.net.redis.RoleRepo;
import com.xxkk.gameCore.net.sql.mapper.UserInfoMapper;
import com.xxkk.gameCore.net.sql.pojo.ServerInfo;
import com.xxkk.gameCore.net.sql.pojo.UserInfo;
import com.xxkk.gameCore.proto.bo.AccountProBuf;
import com.xxkk.gameCore.proto.bo.BoProBuf;
import com.xxkk.gameCore.vo.AreaVo;
import com.xxkk.gameCore.vo.BusinessError;
import com.xxkk.gameCore.vo.Role;
import com.xxkk.gameCore.vo.ServerVo;
import com.xxkk.mvc.service.SqlService;
import com.xxkk.net.websocketNetty.Player;
import com.xxkk.utils.JsonUtils;
import com.xxkk.utils.TimeUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author xxkk
 * @version 1.0.0
 * @title AccountService
 * @description ʕ•ᴥ•ʔ 注册登陆等功能接口实现
 * @create 2023/11/22 14:36
 **/
@Service
public class AccountService {
    private final static Logger logger = Logger.getLogger(AccountService.class);
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private RoleRepo roleRepo;
    @Autowired
    private SqlService sqlService;
    @Autowired
    private ServerData serverData;
    @Autowired
    private ServerManager serverManager;

    /**
     * 注册功能:如果该账户不存在则注册
     *
     * @param account 账号
     * @param pwd     密码
     * @return 成功注册则返回userInfoVo，失败返回错误码（string）
     */
    public Builder registerAccount(String account, String pwd, Player player) {
        UserInfo userInfo1 = this.sqlService.getUserInfoByAccount(account);
        if (userInfo1 == null) {  // mysql判断账户不存在
            UserInfo userInfo = new UserInfo(); // 创建并insert mysql账户数据
            userInfo.setAccount(account);
            userInfo.setPassword(pwd);
            String newPlatformId = this.roleRepo.newPlatformId();// 向redis申请平台id
            userInfo.setPlatformId(newPlatformId);
            userInfo.setRegisterIp(player.getLoginIp());// 设置注册ip
            userInfo.setCreated(TimeUtil.getDate());// 设置注册时间
            userInfo.setLastLoginIp(player.getLoginIp());//设置最后登陆ip
            userInfo.setUpdated(TimeUtil.getDate());// 设置最后登陆时间
            int res = this.userInfoMapper.insertSelective(userInfo);
            if (res > 0) {
                userInfo = this.sqlService.getUserInfoByAccount(account);
                logger.info("用户注册成功：" + userInfo);
                return userInfo.builder(userInfo);// 返回用户信息
            } else {
                logger.info(ErrorCode.sqlException);
                return new BusinessError(ErrorCode.sqlException).newBuilder();
            }
        } else {
            logger.info("用户注册失败,用户已存在：" + userInfo1.toString());
            return new BusinessError(ErrorCode.alreadyExistsUser).newBuilder();
        }
    }

    /**
     * 获取用户信息的接口
     */
    public Builder getUserInfo(String account, String password, Player player) {
        UserInfo userInfo = this.sqlService.getUserInfoByAP(account, password);
        if (userInfo == null) {
            return new BusinessError(ErrorCode.accountCheckedError).newBuilder();
        }
        return UserInfo.builder(userInfo);
    }

    /**
     * 用户登陆接口
     * 账号密码验证>刷新角色信息>保存状态>返回前端数据
     *
     * @param player 客户端调用自动填充的玩家对象
     * @return
     */
    public Builder login(String account, String password, int areaId, String platformId, Player player) {
        if (!this.serverData.hasSelfArea(areaId)) // 验证区是否存在
            return new BusinessError(ErrorCode.noArea).newBuilder();

        UserInfo userInfo = this.sqlService.getUserInfoByAPP(account, password, platformId);
        if (userInfo == null) //验证账号是否正确
            return new BusinessError(ErrorCode.accountCheckedError).newBuilder();

        //验证其它（封号等验证）暂时不做

        int serverId = this.serverData.getSelfServerInfo().getServerId();
        Role role = this.getRoleFromUserInfoState(userInfo, serverId, areaId, platformId);

        this.refreashRoleInfo(role, userInfo, areaId, platformId, player);//刷新玩家角色

        player.setPlatformId(platformId);//修改上下文中登陆玩家状态
        player.setRoleId(role.getRoleId());
        player.setAreaId(areaId);
        this.serverManager.rmConnectingPlayer(player.getPlayerId());
        Player oldPlayer = this.serverManager.addPlayer(player, areaId);
        if (oldPlayer != null)
            oldPlayer.close();// 挤号退出
        player.setPlayerState(PlayerState.onLine);//设置玩家状态为在线

        //构建登陆返回数据
        AccountProBuf.LoginRespProto.Builder builder = AccountProBuf.LoginRespProto.newBuilder();
        builder.setState("success");
        builder.setRoleInfo((AccountProBuf.RoleInfoProto.Builder) role.build());
        return builder;
    }

    //私有方法，从玩家state中获取角色信息，如果没有则创建新角色
    private Role getRoleFromUserInfoState(UserInfo userInfo, int serverId, int areaId, String platformId) {
        Object state = userInfo.getState();
        long roleId = 0;
        Role role = null;

        if (state == null) { // 没有玩家ID则创建
            roleId = this.roleRepo.newRoleId();// newRole
            role = new Role();
            role.setRoleId(roleId);
            role.setPlatformId(platformId);
            role.setAreaId(areaId);

            List<AreaVo> areaVos = new ArrayList<>();// newServerVos
            areaVos.add(new AreaVo(areaId, roleId));
            ServerVo serverVo = new ServerVo(this.serverData.getSelfServerInfo().getServerId(), areaVos);
            List<ServerVo> serverVos = new ArrayList<>();
            serverVos.add(serverVo);

            JSONObject jsonObject = new JSONObject();// toJson
            jsonObject.put("servers", serverVos);
            userInfo.setState(jsonObject.toString());

            boolean flag = this.sqlService.updateUserInfo(userInfo);
            if (!flag)
                throw new BusinessError("sql更新异常");
            this.roleRepo.saveRole(role);// save
            return role;//返回
        } else {
            JSONObject jsonObject = JsonUtils.toJsonObj(state);
//            Map<String,List<ServerVo>> map  = (Map<String, List<ServerVo>>) jsonObject.get("servers");
//            JSONArray jsonArray = (JSONArray) jsonObject.get("servers");
//            logger.info(jsonArray.toString());
            List<ServerVo> arr = JSON.parseArray(jsonObject.get("servers").toString(), ServerVo.class);
            for (ServerVo serverVo : arr) {
                if (serverVo.getSelectedServerId() == serverId) {
                    for (AreaVo areaVo : serverVo.getAreaVos()) {
                        if (areaVo.getAreaId() == areaId) {
                            roleId = areaVo.getRoleId();
                        }
                    }
                }
            }
            if (roleId == 0) {
                throw new RuntimeException("玩家state信息中没找到roleId");
            }
            role = this.roleRepo.getRole(roleId);
            logger.info("获取角色信息：" + role.toString());
            return role;
        }
    }

    private Role refreashRoleInfo(Role role, UserInfo userInfo, int areaId, String platformId, Player player) {
        role.refreshLastLoginTime();
        this.roleRepo.saveRole(role);
        logger.info("#刷新角色信息" + role.toString());
        return role;
    }

    /**
     * 获取所有逻辑服务器区服信息
     *
     * @return 逻辑服务器信息，区信息的json数据
     */
    public Builder getServerInfos(Player player) {
        List<ServerInfo> list = this.serverData.getAllServerInfoForFront();
        BoProBuf.StringProto.Builder builder = BoProBuf.StringProto.newBuilder();
        builder.setStr(JsonUtils.toJsonString(list));
        return builder;
    }

    /**
     * 更新玩家状态信息，更新玩家已登陆的服务器信息
     *
     * @param APP     账号密码用,分割（account,password,platformId）
     * @param jsonStr 玩家完整的state的json格式字符串信息
     * @deprecated 弃用！！！
     */
    private Builder updateUserInfoState(String APP, String jsonStr, Player player) {
        String[] list = APP.split(",");
        UserInfo userInfo = this.sqlService.getUserInfoByAPP(list[0], list[1], list[2]);
        if (userInfo == null) {
            return new BusinessError(ErrorCode.noUser).newBuilder();
        }
        JSONObject jsonObject = null;
        try {
            jsonObject = JsonUtils.toJsonObj(jsonStr);
        } catch (Exception e) {
            e.printStackTrace();
            return new BusinessError(ErrorCode.jsonTransformError).newBuilder();
        }
        userInfo.setState(jsonObject.toString());// 顺便刷新时间
        boolean flag = this.sqlService.updateUserInfo(userInfo);
        return BoProBuf.BoolProto.newBuilder().setBol(flag);
    }

    /**
     * 玩家选区接口
     *
     * @param APP    账号密码用,分割（account,password,platformId）
     * @param areaId 所选区id
     * @param player
     * @return
     * @deprecated 弃用!!!
     */
    private Builder selectServerAndArea(String APP, int serverId, int areaId, Player player) {
        String[] list = APP.split(",");
        UserInfo userInfo = this.sqlService.getUserInfoByAPP(list[0], list[1], list[2]);
        if (userInfo == null) {
            return new BusinessError(ErrorCode.noUser).newBuilder();
        }
        JSONObject jsonObject;
        Object state = userInfo.getState();
        if (state == null) {
            jsonObject = new JSONObject();
            List<AreaVo> areaVos = new ArrayList<>();
            areaVos.add(new AreaVo(areaId, -10000));
            ServerVo serverVo = new ServerVo(serverId, areaVos);
            List<ServerVo> serverVos = new ArrayList<>();
            serverVos.add(serverVo);
            jsonObject.put("servers", serverVos);
            userInfo.setState(jsonObject.toString());
        }
        boolean flag = this.sqlService.updateUserInfo(userInfo);
        return flag ? UserInfo.builder(userInfo) : new BusinessError(ErrorCode.sqlException).newBuilder();
    }

}
